Micron Document
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
| SparkN0de-git | SparkN0de |
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------


Displaying Raw • Download


meshchatx/src/backend/i2p_support.py fa46dc4ce9ab50cbe66a7a9e4b3bca0140102345 (fa46dc4c) Text, 11.83 KB

T8b949e# SPDX-License-Identifier: 0BSD

T8b949e"""I2PInterface safety helpers for MeshChatX.

Reticulum's I2P interface is fragile: only one should exist, it must be the
last interface in the config, and transport mode must already be enabled.
Adding I2P via raw config/import or leaving it mid-list after later edits can
brick startup (on Android that previously meant wiping the whole app).

These helpers enforce the constraints on API writes and repair unsafe configs
before Reticulum starts so identity/storage survive.
"""

Tff7b72from T7ee787__future__ Tff7b72import Te6edf3annotations

Tff7b72import T7ee787logging
Tff7b72import T7ee787os
Tff7b72from T7ee787typing Tff7b72import Te6edf3Any

Te6edf3logger Tff7b72= Te6edf3loggingTff7b72.Td2a8ffgetLoggerTb4b4b4(Tff7b72__name__Tb4b4b4)

Te6edf3_TRUE_STRINGS Tff7b72= Tb4b4b4(Ta5d6ff"Ta5d6fftrueTa5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ffyesTa5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ff1Ta5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ffonTa5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ffyTa5d6ff"Tb4b4b4)

Te6edf3I2P_TYPE Tff7b72= Ta5d6ff"Ta5d6ffI2PInterfaceTa5d6ff"

Te6edf3MSG_TRANSPORT_REQUIRED Tff7b72= Tb4b4b4(
Ta5d6ff"Ta5d6ffTransport mode must be enabled before adding or enabling an I2P interface. Ta5d6ff"
Ta5d6ff"Ta5d6ffEnable it in Settings, then add I2P as the last interface.Ta5d6ff"
Tb4b4b4)
Te6edf3MSG_ONLY_ONE Tff7b72= Tb4b4b4(
Ta5d6ff"Ta5d6ffOnly one I2P interface is allowed. Remove or disable the existing I2P Ta5d6ff"
Ta5d6ff"Ta5d6ffinterface before adding another.Ta5d6ff"
Tb4b4b4)
Te6edf3MSG_IMPORT_FORBIDDEN Tff7b72= Tb4b4b4(
Ta5d6ff"Ta5d6ffI2P interfaces cannot be imported from a config file. Add I2P only through Ta5d6ff"
Ta5d6ff"Ta5d6ffthe Add Interface page, with transport mode already enabled, as the last Ta5d6ff"
Ta5d6ff"Ta5d6ffinterface.Ta5d6ff"
Tb4b4b4)
Te6edf3MSG_RAW_FORBIDDEN Tff7b72= Tb4b4b4(
Ta5d6ff"Ta5d6ffI2P interfaces cannot be added or changed through the raw config editor. Ta5d6ff"
Ta5d6ff"Ta5d6ffUse the Add Interface page (transport must already be enabled), or delete Ta5d6ff"
Ta5d6ff"Ta5d6ffthe I2P section from the file to recover.Ta5d6ff"
Tb4b4b4)
Te6edf3MSG_MUST_BE_LAST Tff7b72= Tb4b4b4(
Ta5d6ff"Ta5d6ffThe I2P interface must be the last interface in the Reticulum config. Ta5d6ff"
Ta5d6ff"Ta5d6ffRemove interfaces added after it, or delete I2P and re-add it last.Ta5d6ff"
Tb4b4b4)


Tff7b72def Td2a8ffis_i2p_interfaceTb4b4b4(Te6edf3ifaceTb4b4b4: Tffa657objectTb4b4b4) Tff7b72-Tff7b72> Tffa657boolTb4b4b4:
Tff7b72if Tff7b72not Tffa657isinstanceTb4b4b4(Te6edf3ifaceTb4b4b4, Tffa657dictTb4b4b4)Tb4b4b4:
Tff7b72return Tff7b72False
Tff7b72return Tffa657strTb4b4b4(Te6edf3ifaceTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6fftypeTa5d6ff"Tb4b4b4) Tff7b72or Ta5d6ff"Ta5d6ff"Tb4b4b4)Tff7b72.Td2a8ffstripTb4b4b4(Tb4b4b4) Tff7b72== Te6edf3I2P_TYPE


Tff7b72def Td2a8ff_parse_boolTb4b4b4(Te6edf3valueTb4b4b4: Tffa657objectTb4b4b4, Tff7b72*Tb4b4b4, Te6edf3defaultTb4b4b4: Tffa657bool Tff7b72= Tff7b72FalseTb4b4b4) Tff7b72-Tff7b72> Tffa657boolTb4b4b4:
Tff7b72if Te6edf3value Tff7b72is Tff7b72None Tff7b72or Te6edf3value Tff7b72== Ta5d6ff"Ta5d6ff"Tb4b4b4:
Tff7b72return Te6edf3default
Tff7b72if Tffa657isinstanceTb4b4b4(Te6edf3valueTb4b4b4, Tffa657boolTb4b4b4)Tb4b4b4:
Tff7b72return Te6edf3value
Tff7b72return Tffa657strTb4b4b4(Te6edf3valueTb4b4b4)Tff7b72.Td2a8ffstripTb4b4b4(Tb4b4b4)Tff7b72.Td2a8fflowerTb4b4b4(Tb4b4b4) Tff7b72in Te6edf3_TRUE_STRINGS


Tff7b72def Td2a8ffis_interface_enabledTb4b4b4(Te6edf3ifaceTb4b4b4: Tffa657dictTb4b4b4) Tff7b72-Tff7b72> Tffa657boolTb4b4b4:
Tff7b72for Te6edf3key Tff7b72in Tb4b4b4(Ta5d6ff"Ta5d6ffinterface_enabledTa5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ffenabledTa5d6ff"Tb4b4b4)Tb4b4b4:
Tff7b72if Te6edf3key Tff7b72in Te6edf3ifaceTb4b4b4:
Tff7b72return Te6edf3_parse_boolTb4b4b4(Te6edf3ifaceTff7b72.Td2a8ffgetTb4b4b4(Te6edf3keyTb4b4b4)Tb4b4b4, Te6edf3defaultTff7b72=Tff7b72FalseTb4b4b4)
Tff7b72return Tff7b72False


Tff7b72def Td2a8fftransport_enabled_in_sectionTb4b4b4(Te6edf3reticulum_sectionTb4b4b4: Tffa657objectTb4b4b4) Tff7b72-Tff7b72> Tffa657boolTb4b4b4:
Tff7b72if Tff7b72not Tffa657isinstanceTb4b4b4(Te6edf3reticulum_sectionTb4b4b4, Tffa657dictTb4b4b4)Tb4b4b4:
Tff7b72return Tff7b72False
Tff7b72return Te6edf3_parse_boolTb4b4b4(Te6edf3reticulum_sectionTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6ffenable_transportTa5d6ff"Tb4b4b4)Tb4b4b4, Te6edf3defaultTff7b72=Tff7b72FalseTb4b4b4)


Tff7b72def Td2a8fflist_i2p_namesTb4b4b4(Te6edf3interfacesTb4b4b4: Tffa657objectTb4b4b4) Tff7b72-Tff7b72> Tffa657listTb4b4b4[Tffa657strTb4b4b4]Tb4b4b4:
Tff7b72if Tff7b72not Tffa657isinstanceTb4b4b4(Te6edf3interfacesTb4b4b4, Tffa657dictTb4b4b4)Tb4b4b4:
Tff7b72return Tb4b4b4[Tb4b4b4]
Tff7b72return Tb4b4b4[Te6edf3name Tff7b72for Te6edf3nameTb4b4b4, Te6edf3iface Tff7b72in Te6edf3interfacesTff7b72.Td2a8ffitemsTb4b4b4(Tb4b4b4) Tff7b72if Te6edf3is_i2p_interfaceTb4b4b4(Te6edf3ifaceTb4b4b4)Tb4b4b4]


Tff7b72def Td2a8ff_i2p_block_is_suffixTb4b4b4(Te6edf3interfacesTb4b4b4: Tffa657dictTb4b4b4) Tff7b72-Tff7b72> Tffa657boolTb4b4b4:
T8b949e"""True when every I2P entry is at the end (no non-I2P after the first I2P)."""
Te6edf3seen_i2p Tff7b72= Tff7b72False
Tff7b72for Te6edf3_nameTb4b4b4, Te6edf3iface Tff7b72in Te6edf3interfacesTff7b72.Td2a8ffitemsTb4b4b4(Tb4b4b4)Tb4b4b4:
Tff7b72if Te6edf3is_i2p_interfaceTb4b4b4(Te6edf3ifaceTb4b4b4)Tb4b4b4:
Te6edf3seen_i2p Tff7b72= Tff7b72True
Tff7b72elif Te6edf3seen_i2pTb4b4b4:
Tff7b72return Tff7b72False
Tff7b72return Tff7b72True


Tff7b72def Td2a8ffi2p_is_lastTb4b4b4(Te6edf3interfacesTb4b4b4: Tffa657objectTb4b4b4) Tff7b72-Tff7b72> Tffa657boolTb4b4b4:
Tff7b72if Tff7b72not Tffa657isinstanceTb4b4b4(Te6edf3interfacesTb4b4b4, Tffa657dictTb4b4b4) Tff7b72or Tff7b72not Te6edf3interfacesTb4b4b4:
Tff7b72return Tff7b72True
Tff7b72if Tff7b72not Te6edf3list_i2p_namesTb4b4b4(Te6edf3interfacesTb4b4b4)Tb4b4b4:
Tff7b72return Tff7b72True
Tff7b72return Te6edf3_i2p_block_is_suffixTb4b4b4(Te6edf3interfacesTb4b4b4)


Tff7b72def Td2a8ffvalidate_i2p_add_or_updateTb4b4b4(
Te6edf3interfacesTb4b4b4: Tffa657objectTb4b4b4,
Te6edf3reticulum_sectionTb4b4b4: Tffa657objectTb4b4b4,
Tff7b72*Tb4b4b4,
Te6edf3interface_nameTb4b4b4: Tffa657strTb4b4b4,
Te6edf3interface_typeTb4b4b4: Tffa657strTb4b4b4,
Te6edf3updating_existingTb4b4b4: Tffa657boolTb4b4b4,
Tb4b4b4) Tff7b72-Tff7b72> Tffa657str Tff7b72| Tff7b72NoneTb4b4b4:
T8b949e"""Return an error message when adding/updating I2P is unsafe, else None."""
Tff7b72if Tffa657strTb4b4b4(Te6edf3interface_type Tff7b72or Ta5d6ff"Ta5d6ff"Tb4b4b4)Tff7b72.Td2a8ffstripTb4b4b4(Tb4b4b4) Tff7b72!= Te6edf3I2P_TYPETb4b4b4:
Tff7b72return Tff7b72None
Tff7b72if Tff7b72not Te6edf3transport_enabled_in_sectionTb4b4b4(Te6edf3reticulum_sectionTb4b4b4)Tb4b4b4:
Tff7b72return Te6edf3MSG_TRANSPORT_REQUIRED
Tff7b72if Tff7b72not Tffa657isinstanceTb4b4b4(Te6edf3interfacesTb4b4b4, Tffa657dictTb4b4b4)Tb4b4b4:
Te6edf3interfaces Tff7b72= Tb4b4b4{Tb4b4b4}
Te6edf3existing Tff7b72= Te6edf3list_i2p_namesTb4b4b4(Te6edf3interfacesTb4b4b4)
Tff7b72if Te6edf3updating_existingTb4b4b4:
Te6edf3others Tff7b72= Tb4b4b4[Te6edf3n Tff7b72for Te6edf3n Tff7b72in Te6edf3existing Tff7b72if Te6edf3n Tff7b72!= Te6edf3interface_nameTb4b4b4]
Tff7b72if Te6edf3othersTb4b4b4:
Tff7b72return Te6edf3MSG_ONLY_ONE
Tff7b72return Tff7b72None
Tff7b72if Te6edf3existingTb4b4b4:
Tff7b72return Te6edf3MSG_ONLY_ONE
Tff7b72return Tff7b72None


Tff7b72def Td2a8ffvalidate_i2p_enableTb4b4b4(
Te6edf3interfacesTb4b4b4: Tffa657objectTb4b4b4,
Te6edf3reticulum_sectionTb4b4b4: Tffa657objectTb4b4b4,
Tff7b72*Tb4b4b4,
Te6edf3interface_nameTb4b4b4: Tffa657strTb4b4b4,
Tb4b4b4) Tff7b72-Tff7b72> Tffa657str Tff7b72| Tff7b72NoneTb4b4b4:
Tff7b72if Tff7b72not Tffa657isinstanceTb4b4b4(Te6edf3interfacesTb4b4b4, Tffa657dictTb4b4b4)Tb4b4b4:
Tff7b72return Tff7b72None
Te6edf3target Tff7b72= Te6edf3interfacesTff7b72.Td2a8ffgetTb4b4b4(Te6edf3interface_nameTb4b4b4)
Tff7b72if Tff7b72not Te6edf3is_i2p_interfaceTb4b4b4(Te6edf3targetTb4b4b4)Tb4b4b4:
Tff7b72return Tff7b72None
Tff7b72if Tff7b72not Te6edf3transport_enabled_in_sectionTb4b4b4(Te6edf3reticulum_sectionTb4b4b4)Tb4b4b4:
Tff7b72return Te6edf3MSG_TRANSPORT_REQUIRED
Te6edf3others_enabled Tff7b72= Tb4b4b4[
Te6edf3n
Tff7b72for Te6edf3n Tff7b72in Te6edf3list_i2p_namesTb4b4b4(Te6edf3interfacesTb4b4b4)
Tff7b72if Te6edf3n Tff7b72!= Te6edf3interface_name Tff7b72and Te6edf3is_interface_enabledTb4b4b4(Te6edf3interfacesTff7b72.Td2a8ffgetTb4b4b4(Te6edf3nTb4b4b4) Tff7b72or Tb4b4b4{Tb4b4b4}Tb4b4b4)
Tb4b4b4]
Tff7b72if Te6edf3others_enabledTb4b4b4:
Tff7b72return Te6edf3MSG_ONLY_ONE
Tff7b72return Tff7b72None


Tff7b72def Td2a8ffvalidate_no_i2p_in_importTb4b4b4(Te6edf3interface_configTb4b4b4: Tffa657dictTb4b4b4) Tff7b72-Tff7b72> Tffa657str Tff7b72| Tff7b72NoneTb4b4b4:
Tff7b72for Te6edf3nameTb4b4b4, Te6edf3body Tff7b72in Te6edf3interface_configTff7b72.Td2a8ffitemsTb4b4b4(Tb4b4b4)Tb4b4b4:
Tff7b72if Te6edf3is_i2p_interfaceTb4b4b4(Te6edf3bodyTb4b4b4)Tb4b4b4:
Tff7b72return Ta5d6fffTa5d6ff'Tffd700{Te6edf3MSG_IMPORT_FORBIDDENTffd700}Ta5d6ff (rejected Ta5d6ff"Tffd700{Te6edf3nameTffd700}Ta5d6ff"Ta5d6ff)Ta5d6ff'
Tff7b72return Tff7b72None


Tff7b72def Td2a8ffreorder_interfaces_i2p_lastTb4b4b4(Te6edf3interfacesTb4b4b4: Tffa657dictTb4b4b4) Tff7b72-Tff7b72> Tffa657boolTb4b4b4:
T8b949e"""Move all I2P sections to the end. Returns True when order changed."""
Tff7b72if Tff7b72not Tffa657isinstanceTb4b4b4(Te6edf3interfacesTb4b4b4, Tffa657dictTb4b4b4) Tff7b72or Tff7b72not Te6edf3interfacesTb4b4b4:
Tff7b72return Tff7b72False
Tff7b72if Te6edf3_i2p_block_is_suffixTb4b4b4(Te6edf3interfacesTb4b4b4)Tb4b4b4:
Tff7b72return Tff7b72False

Te6edf3non_i2pTb4b4b4: Tffa657listTb4b4b4[Tffa657tupleTb4b4b4[Tffa657strTb4b4b4, Te6edf3AnyTb4b4b4]Tb4b4b4] Tff7b72= Tb4b4b4[Tb4b4b4]
Te6edf3i2pTb4b4b4: Tffa657listTb4b4b4[Tffa657tupleTb4b4b4[Tffa657strTb4b4b4, Te6edf3AnyTb4b4b4]Tb4b4b4] Tff7b72= Tb4b4b4[Tb4b4b4]
Tff7b72for Te6edf3nameTb4b4b4, Te6edf3iface Tff7b72in Tffa657listTb4b4b4(Te6edf3interfacesTff7b72.Td2a8ffitemsTb4b4b4(Tb4b4b4)Tb4b4b4)Tb4b4b4:
Tff7b72if Te6edf3is_i2p_interfaceTb4b4b4(Te6edf3ifaceTb4b4b4)Tb4b4b4:
Te6edf3i2pTff7b72.Td2a8ffappendTb4b4b4(Tb4b4b4(Te6edf3nameTb4b4b4, Te6edf3ifaceTb4b4b4)Tb4b4b4)
Tff7b72elseTb4b4b4:
Te6edf3non_i2pTff7b72.Td2a8ffappendTb4b4b4(Tb4b4b4(Te6edf3nameTb4b4b4, Te6edf3ifaceTb4b4b4)Tb4b4b4)
Tff7b72if Tff7b72not Te6edf3i2pTb4b4b4:
Tff7b72return Tff7b72False

Tff7b72for Te6edf3name Tff7b72in Tffa657listTb4b4b4(Te6edf3interfacesTff7b72.Td2a8ffkeysTb4b4b4(Tb4b4b4)Tb4b4b4)Tb4b4b4:
Tff7b72del Te6edf3interfacesTb4b4b4[Te6edf3nameTb4b4b4]
Tff7b72for Te6edf3nameTb4b4b4, Te6edf3iface Tff7b72in Te6edf3non_i2p Tff7b72+ Te6edf3i2pTb4b4b4:
Te6edf3interfacesTb4b4b4[Te6edf3nameTb4b4b4] Tff7b72= Te6edf3iface
Tff7b72return Tff7b72True


Tff7b72def Td2a8ffenforce_single_enabled_i2pTb4b4b4(Te6edf3interfacesTb4b4b4: Tffa657dictTb4b4b4) Tff7b72-Tff7b72> Tffa657boolTb4b4b4:
T8b949e"""Disable all but the first enabled I2P interface. Returns True if changed."""
Tff7b72if Tff7b72not Tffa657isinstanceTb4b4b4(Te6edf3interfacesTb4b4b4, Tffa657dictTb4b4b4)Tb4b4b4:
Tff7b72return Tff7b72False
Te6edf3modified Tff7b72= Tff7b72False
Te6edf3keptTb4b4b4: Tffa657str Tff7b72| Tff7b72None Tff7b72= Tff7b72None
Tff7b72for Te6edf3nameTb4b4b4, Te6edf3iface Tff7b72in Te6edf3interfacesTff7b72.Td2a8ffitemsTb4b4b4(Tb4b4b4)Tb4b4b4:
Tff7b72if Tff7b72not Te6edf3is_i2p_interfaceTb4b4b4(Te6edf3ifaceTb4b4b4)Tb4b4b4:
Tff7b72continue
Tff7b72if Tff7b72not Te6edf3is_interface_enabledTb4b4b4(Te6edf3ifaceTb4b4b4)Tb4b4b4:
Tff7b72continue
Tff7b72if Te6edf3kept Tff7b72is Tff7b72NoneTb4b4b4:
Te6edf3kept Tff7b72= Te6edf3name
Tff7b72continue
Te6edf3ifaceTb4b4b4[Ta5d6ff"Ta5d6ffinterface_enabledTa5d6ff"Tb4b4b4] Tff7b72= Ta5d6ff"Ta5d6fffalseTa5d6ff"
Tff7b72if Ta5d6ff"Ta5d6ffenabledTa5d6ff" Tff7b72in Te6edf3ifaceTb4b4b4:
Te6edf3ifaceTb4b4b4[Ta5d6ff"Ta5d6ffenabledTa5d6ff"Tb4b4b4] Tff7b72= Ta5d6ff"Ta5d6fffalseTa5d6ff"
Te6edf3modified Tff7b72= Tff7b72True
Te6edf3loggerTff7b72.Td2a8ffwarningTb4b4b4(
Ta5d6ff'Ta5d6ffDisabled extra I2P interface Ta5d6ff"Tffd700%sTa5d6ff"Ta5d6ff (only one I2P interface is allowed; Ta5d6ff'
Ta5d6ff'Ta5d6ffkept Ta5d6ff"Tffd700%sTa5d6ff"Ta5d6ff)Ta5d6ff'Tb4b4b4,
Te6edf3nameTb4b4b4,
Te6edf3keptTb4b4b4,
Tb4b4b4)
Tff7b72return Te6edf3modified


Tff7b72def Td2a8ffdisable_i2p_when_transport_offTb4b4b4(
Te6edf3interfacesTb4b4b4: Tffa657dictTb4b4b4,
Te6edf3reticulum_sectionTb4b4b4: Tffa657objectTb4b4b4,
Tb4b4b4) Tff7b72-Tff7b72> Tffa657boolTb4b4b4:
Tff7b72if Te6edf3transport_enabled_in_sectionTb4b4b4(Te6edf3reticulum_sectionTb4b4b4)Tb4b4b4:
Tff7b72return Tff7b72False
Tff7b72if Tff7b72not Tffa657isinstanceTb4b4b4(Te6edf3interfacesTb4b4b4, Tffa657dictTb4b4b4)Tb4b4b4:
Tff7b72return Tff7b72False
Te6edf3modified Tff7b72= Tff7b72False
Tff7b72for Te6edf3nameTb4b4b4, Te6edf3iface Tff7b72in Te6edf3interfacesTff7b72.Td2a8ffitemsTb4b4b4(Tb4b4b4)Tb4b4b4:
Tff7b72if Tff7b72not Te6edf3is_i2p_interfaceTb4b4b4(Te6edf3ifaceTb4b4b4)Tb4b4b4:
Tff7b72continue
Tff7b72if Tff7b72not Te6edf3is_interface_enabledTb4b4b4(Te6edf3ifaceTb4b4b4)Tb4b4b4:
Tff7b72continue
Te6edf3ifaceTb4b4b4[Ta5d6ff"Ta5d6ffinterface_enabledTa5d6ff"Tb4b4b4] Tff7b72= Ta5d6ff"Ta5d6fffalseTa5d6ff"
Tff7b72if Ta5d6ff"Ta5d6ffenabledTa5d6ff" Tff7b72in Te6edf3ifaceTb4b4b4:
Te6edf3ifaceTb4b4b4[Ta5d6ff"Ta5d6ffenabledTa5d6ff"Tb4b4b4] Tff7b72= Ta5d6ff"Ta5d6fffalseTa5d6ff"
Te6edf3modified Tff7b72= Tff7b72True
Te6edf3loggerTff7b72.Td2a8ffwarningTb4b4b4(
Ta5d6ff'Ta5d6ffDisabled I2P interface Ta5d6ff"Tffd700%sTa5d6ff"Ta5d6ff because enable_transport is offTa5d6ff'Tb4b4b4,
Te6edf3nameTb4b4b4,
Tb4b4b4)
Tff7b72return Te6edf3modified


Tff7b72def Td2a8ffrepair_interfaces_dictTb4b4b4(
Te6edf3interfacesTb4b4b4: Tffa657dictTb4b4b4,
Te6edf3reticulum_sectionTb4b4b4: Tffa657objectTb4b4b4,
Tb4b4b4) Tff7b72-Tff7b72> Tffa657boolTb4b4b4:
T8b949e"""Apply all in-memory I2P safety repairs. Returns True when anything changed."""
Tff7b72if Tff7b72not Tffa657isinstanceTb4b4b4(Te6edf3interfacesTb4b4b4, Tffa657dictTb4b4b4)Tb4b4b4:
Tff7b72return Tff7b72False
Te6edf3modified Tff7b72= Tff7b72False
Tff7b72if Te6edf3enforce_single_enabled_i2pTb4b4b4(Te6edf3interfacesTb4b4b4)Tb4b4b4:
Te6edf3modified Tff7b72= Tff7b72True
Tff7b72if Te6edf3disable_i2p_when_transport_offTb4b4b4(Te6edf3interfacesTb4b4b4, Te6edf3reticulum_sectionTb4b4b4)Tb4b4b4:
Te6edf3modified Tff7b72= Tff7b72True
Tff7b72if Te6edf3reorder_interfaces_i2p_lastTb4b4b4(Te6edf3interfacesTb4b4b4)Tb4b4b4:
Te6edf3modified Tff7b72= Tff7b72True
Te6edf3loggerTff7b72.Td2a8ffwarningTb4b4b4(
Ta5d6ff"Ta5d6ffMoved I2P interface(s) to the end of [interfaces] for safe startupTa5d6ff"Tb4b4b4,
Tb4b4b4)
Tff7b72return Te6edf3modified


Tff7b72def Td2a8ffexisting_i2p_names_from_config_pathTb4b4b4(Te6edf3config_pathTb4b4b4: Tffa657strTb4b4b4) Tff7b72-Tff7b72> Tffa657setTb4b4b4[Tffa657strTb4b4b4]Tb4b4b4:
Tff7b72if Tff7b72not Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffisfileTb4b4b4(Te6edf3config_pathTb4b4b4)Tb4b4b4:
Tff7b72return Tffa657setTb4b4b4(Tb4b4b4)
Tff7b72tryTb4b4b4:
Tff7b72from T7ee787RNST7ee787.T7ee787vendorT7ee787.T7ee787configobj Tff7b72import Te6edf3ConfigObj

Te6edf3cfg Tff7b72= Te6edf3ConfigObjTb4b4b4(Te6edf3config_pathTb4b4b4)
Tff7b72except Tf85149ExceptionTb4b4b4:
Tff7b72return Tffa657setTb4b4b4(Tb4b4b4)
Te6edf3interfaces Tff7b72= Te6edf3cfgTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6ffinterfacesTa5d6ff"Tb4b4b4)
Tff7b72return Tffa657setTb4b4b4(Te6edf3list_i2p_namesTb4b4b4(Te6edf3interfacesTb4b4b4)Tb4b4b4)


Tff7b72def Td2a8ff_iface_snapshotTb4b4b4(Te6edf3ifaceTb4b4b4: Tffa657dictTb4b4b4) Tff7b72-Tff7b72> Tffa657dictTb4b4b4:
Te6edf3out Tff7b72= Tb4b4b4{Tb4b4b4}
Tff7b72for Te6edf3keyTb4b4b4, Te6edf3value Tff7b72in Te6edf3ifaceTff7b72.Td2a8ffitemsTb4b4b4(Tb4b4b4)Tb4b4b4:
Tff7b72if Tffa657isinstanceTb4b4b4(Te6edf3valueTb4b4b4, Tffa657dictTb4b4b4)Tb4b4b4:
Tff7b72continue
Te6edf3outTb4b4b4[Tffa657strTb4b4b4(Te6edf3keyTb4b4b4)Tb4b4b4] Tff7b72= Te6edf3value
Tff7b72return Te6edf3out


Tff7b72def Td2a8ffvalidate_raw_config_i2p_policyTb4b4b4(
Te6edf3contentTb4b4b4: Tffa657strTb4b4b4,
Tff7b72*Tb4b4b4,
Te6edf3previous_interfacesTb4b4b4: Tffa657dict Tff7b72| Tff7b72None Tff7b72= Tff7b72NoneTb4b4b4,
Tb4b4b4) Tff7b72-Tff7b72> Tffa657str Tff7b72| Tff7b72NoneTb4b4b4:
T8b949e"""Reject raw edits that add or alter I2P stanzas via the file editor.

Deleting an existing I2P section is allowed (recovery path). Adding I2P or
changing an existing I2P stanza through raw text is not.
"""
Tff7b72tryTb4b4b4:
Tff7b72from T7ee787RNST7ee787.T7ee787vendorT7ee787.T7ee787configobj Tff7b72import Te6edf3ConfigObj
Tff7b72except Tf85149ExceptionTb4b4b4:
Tff7b72return Tff7b72None

Tff7b72tryTb4b4b4:
Te6edf3cfg Tff7b72= Te6edf3ConfigObjTb4b4b4(Te6edf3contentTff7b72.Td2a8ffsplitlinesTb4b4b4(Tb4b4b4)Tb4b4b4)
Tff7b72except Tf85149ExceptionTb4b4b4:
Tff7b72return Tff7b72None

Te6edf3interfaces Tff7b72= Te6edf3cfgTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6ffinterfacesTa5d6ff"Tb4b4b4)
Tff7b72if Tff7b72not Tffa657isinstanceTb4b4b4(Te6edf3interfacesTb4b4b4, Tffa657dictTb4b4b4)Tb4b4b4:
Tff7b72return Tff7b72None

Te6edf3prev_ifaces Tff7b72= Te6edf3previous_interfaces Tff7b72if Tffa657isinstanceTb4b4b4(Te6edf3previous_interfacesTb4b4b4, Tffa657dictTb4b4b4) Tff7b72else Tb4b4b4{Tb4b4b4}
Te6edf3prev_names Tff7b72= Tffa657setTb4b4b4(Te6edf3list_i2p_namesTb4b4b4(Te6edf3prev_ifacesTb4b4b4)Tb4b4b4)
Te6edf3new_names Tff7b72= Tffa657setTb4b4b4(Te6edf3list_i2p_namesTb4b4b4(Te6edf3interfacesTb4b4b4)Tb4b4b4)

Tff7b72if Te6edf3new_names Tff7b72- Te6edf3prev_namesTb4b4b4:
Tff7b72return Te6edf3MSG_RAW_FORBIDDEN

Tff7b72if Tffa657lenTb4b4b4(Te6edf3new_namesTb4b4b4) Tff7b72> T79c0ff1Tb4b4b4:
Tff7b72return Te6edf3MSG_ONLY_ONE

Tff7b72if Te6edf3new_names Tff7b72and Tff7b72not Te6edf3_i2p_block_is_suffixTb4b4b4(Te6edf3interfacesTb4b4b4)Tb4b4b4:
Tff7b72return Te6edf3MSG_MUST_BE_LAST

Tff7b72for Te6edf3name Tff7b72in Te6edf3new_names Tff7b72& Te6edf3prev_namesTb4b4b4:
Te6edf3prev_body Tff7b72= Te6edf3prev_ifacesTff7b72.Td2a8ffgetTb4b4b4(Te6edf3nameTb4b4b4) Tff7b72or Tb4b4b4{Tb4b4b4}
Te6edf3new_body Tff7b72= Te6edf3interfacesTff7b72.Td2a8ffgetTb4b4b4(Te6edf3nameTb4b4b4) Tff7b72or Tb4b4b4{Tb4b4b4}
Tff7b72if Tff7b72not Tffa657isinstanceTb4b4b4(Te6edf3prev_bodyTb4b4b4, Tffa657dictTb4b4b4) Tff7b72or Tff7b72not Tffa657isinstanceTb4b4b4(Te6edf3new_bodyTb4b4b4, Tffa657dictTb4b4b4)Tb4b4b4:
Tff7b72return Te6edf3MSG_RAW_FORBIDDEN
Tff7b72if Te6edf3_iface_snapshotTb4b4b4(Te6edf3prev_bodyTb4b4b4) Tff7b72!= Te6edf3_iface_snapshotTb4b4b4(Te6edf3new_bodyTb4b4b4)Tb4b4b4:
Tff7b72return Te6edf3MSG_RAW_FORBIDDEN

Tff7b72return Tff7b72None


Tff7b72def Td2a8ffdisable_all_i2p_in_configTb4b4b4(Te6edf3config_pathTb4b4b4: Tffa657strTb4b4b4) Tff7b72-Tff7b72> Tffa657boolTb4b4b4:
T8b949e"""Disable every I2P interface in *config_path*. Returns True if changed."""
Tff7b72if Tff7b72not Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffisfileTb4b4b4(Te6edf3config_pathTb4b4b4)Tb4b4b4:
Tff7b72return Tff7b72False
Tff7b72tryTb4b4b4:
Tff7b72from T7ee787RNST7ee787.T7ee787vendorT7ee787.T7ee787configobj Tff7b72import Te6edf3ConfigObj

Te6edf3cfg Tff7b72= Te6edf3ConfigObjTb4b4b4(Te6edf3config_pathTb4b4b4)
Tff7b72except Tf85149ExceptionTb4b4b4:
Tff7b72return Tff7b72False
Te6edf3interfaces Tff7b72= Te6edf3cfgTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6ffinterfacesTa5d6ff"Tb4b4b4)
Tff7b72if Tff7b72not Tffa657isinstanceTb4b4b4(Te6edf3interfacesTb4b4b4, Tffa657dictTb4b4b4)Tb4b4b4:
Tff7b72return Tff7b72False
Te6edf3modified Tff7b72= Tff7b72False
Tff7b72for Te6edf3nameTb4b4b4, Te6edf3iface Tff7b72in Te6edf3interfacesTff7b72.Td2a8ffitemsTb4b4b4(Tb4b4b4)Tb4b4b4:
Tff7b72if Tff7b72not Te6edf3is_i2p_interfaceTb4b4b4(Te6edf3ifaceTb4b4b4)Tb4b4b4:
Tff7b72continue
Tff7b72if Tff7b72not Te6edf3is_interface_enabledTb4b4b4(Te6edf3ifaceTb4b4b4)Tb4b4b4:
Tff7b72continue
Te6edf3ifaceTb4b4b4[Ta5d6ff"Ta5d6ffinterface_enabledTa5d6ff"Tb4b4b4] Tff7b72= Ta5d6ff"Ta5d6fffalseTa5d6ff"
Tff7b72if Ta5d6ff"Ta5d6ffenabledTa5d6ff" Tff7b72in Te6edf3ifaceTb4b4b4:
Te6edf3ifaceTb4b4b4[Ta5d6ff"Ta5d6ffenabledTa5d6ff"Tb4b4b4] Tff7b72= Ta5d6ff"Ta5d6fffalseTa5d6ff"
Te6edf3modified Tff7b72= Tff7b72True
Te6edf3loggerTff7b72.Td2a8ffwarningTb4b4b4(
Ta5d6ff'Ta5d6ffDisabled I2P interface Ta5d6ff"Tffd700%sTa5d6ff"Ta5d6ff to recover from a Reticulum startup failureTa5d6ff'Tb4b4b4,
Te6edf3nameTb4b4b4,
Tb4b4b4)
Tff7b72if Tff7b72not Te6edf3modifiedTb4b4b4:
Tff7b72return Tff7b72False
Tff7b72tryTb4b4b4:
Te6edf3cfgTff7b72.Td2a8ffwriteTb4b4b4(Tb4b4b4)
Tff7b72except Tf85149Exception Tff7b72as Te6edf3excTb4b4b4:
Te6edf3loggerTff7b72.Td2a8ffwarningTb4b4b4(Ta5d6ff"Ta5d6ffFailed to disable I2P interfaces in config: Tffd700%sTa5d6ff"Tb4b4b4, Te6edf3excTb4b4b4)
Tff7b72return Tff7b72False
Tff7b72return Tff7b72True


Tff7b72def Td2a8ffguard_i2p_interfaces_in_configTb4b4b4(Te6edf3config_pathTb4b4b4: Tffa657strTb4b4b4) Tff7b72-Tff7b72> Tffa657boolTb4b4b4:
T8b949e"""Repair I2P entries in a Reticulum config file before startup.

Ensures at most one enabled I2P interface, disables I2P when transport is
off, and moves I2P sections to the end of [interfaces].
"""
Tff7b72if Tff7b72not Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffisfileTb4b4b4(Te6edf3config_pathTb4b4b4)Tb4b4b4:
Tff7b72return Tff7b72False
Tff7b72tryTb4b4b4:
Tff7b72from T7ee787RNST7ee787.T7ee787vendorT7ee787.T7ee787configobj Tff7b72import Te6edf3ConfigObj

Te6edf3cfg Tff7b72= Te6edf3ConfigObjTb4b4b4(Te6edf3config_pathTb4b4b4)
Tff7b72except Tf85149Exception Tff7b72as Te6edf3excTb4b4b4:
Te6edf3loggerTff7b72.Td2a8ffwarningTb4b4b4(Ta5d6ff"Ta5d6ffCould not open Reticulum config for I2P guard: Tffd700%sTa5d6ff"Tb4b4b4, Te6edf3excTb4b4b4)
Tff7b72return Tff7b72False

Te6edf3interfaces Tff7b72= Te6edf3cfgTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6ffinterfacesTa5d6ff"Tb4b4b4)
Te6edf3reticulum Tff7b72= Te6edf3cfgTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6ffreticulumTa5d6ff"Tb4b4b4)
Tff7b72if Tff7b72not Tffa657isinstanceTb4b4b4(Te6edf3interfacesTb4b4b4, Tffa657dictTb4b4b4)Tb4b4b4:
Tff7b72return Tff7b72False

Tff7b72if Tff7b72not Te6edf3repair_interfaces_dictTb4b4b4(Te6edf3interfacesTb4b4b4, Te6edf3reticulumTb4b4b4)Tb4b4b4:
Tff7b72return Tff7b72False

Tff7b72tryTb4b4b4:
Te6edf3cfgTff7b72.Td2a8ffwriteTb4b4b4(Tb4b4b4)
Tff7b72except Tf85149Exception Tff7b72as Te6edf3excTb4b4b4:
Te6edf3loggerTff7b72.Td2a8ffwarningTb4b4b4(Ta5d6ff"Ta5d6ffFailed to write I2P-guarded Reticulum config: Tffd700%sTa5d6ff"Tb4b4b4, Te6edf3excTb4b4b4)
Tff7b72return Tff7b72False
Tff7b72return Tff7b72True


──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────